//
//  ASAnisetteDataProvider.m
//  XAuthServer
//
//  Created by 吴双 on 2023/1/22.
//

#import "ASAnisetteDataProvider.h"
#import "ALTAnisetteData+Sanitize.h"
#import "ASError.h"

@implementation ASAnisetteDataProvider

- (void)fetchAnisetteData:(ASAnisetteDataHandler)completion {
    NSAssert(NO, @"Override by subclass.");
}

@end

#if TARGET_OS_OSX

#define NOTIFY_SEND @"com.rileytestut.AltServer.FetchAnisetteData"
#define NOTIFY_RESP @"com.rileytestut.AltServer.AnisetteDataResponse"

@interface ASAnisetteDataLocalProvider ()

@property (nonatomic, strong, readonly) NSMutableDictionary *tasks;

@end

@implementation ASAnisetteDataLocalProvider

- (instancetype)init {
    self = [super init];
    if (self) {
        _tasks = [NSMutableDictionary dictionary];
        [[NSDistributedNotificationCenter defaultCenter] addObserver:self
                                                            selector:@selector(receiveNotification:)
                                                                name:NOTIFY_RESP
                                                              object:nil
                                                  suspensionBehavior:NSNotificationSuspensionBehaviorDeliverImmediately];
    }
    return self;
}

- (void)fetchAnisetteData:(ASAnisetteDataHandler)completion {
    if (![[NSFileManager defaultManager] fileExistsAtPath:@"/Library/Mail/Bundles/AltPlugin.mailbundle"]) {
        NSError *error = [NSError errorWithDomain:ASErrorDomain code:ASErrorMailPluginNotFound userInfo:@{
            NSLocalizedDescriptionKey: @"Login failed",
            NSLocalizedFailureReasonErrorKey: @"Can not found Mail plugin",
            NSLocalizedRecoverySuggestionErrorKey: @"Install Mail plugin",
        }];
        !completion ?: completion(nil, error);
        return;
    }
    
    
    NSString *requestUUID = [NSUUID UUID].UUIDString;
    self.tasks[requestUUID] = completion;
    [[NSDistributedNotificationCenter defaultCenter] postNotificationName:NOTIFY_SEND
                                                                   object:nil
                                                                 userInfo:@{
        @"requestUUID": requestUUID,
    } options:NSDistributedNotificationDeliverImmediately];
    
    __weak __auto_type weak_self = self;
    dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
        __strong __auto_type self = weak_self;
        ASAnisetteDataHandler handler = self.tasks[requestUUID];
        if (handler) {
            self.tasks[requestUUID] = nil;
            NSError *error = [NSError errorWithDomain:ASErrorDomain code:ASErrorMailPluginNotEnable userInfo:@{
                NSLocalizedDescriptionKey: @"Login failed",
                NSLocalizedFailureReasonErrorKey: @"Can not fetch AnisetteData",
                NSLocalizedRecoverySuggestionErrorKey: @"Enable AltPlugin in Mail's preference",
            }];
            handler(nil, error);
        }
    });
}

- (void)receiveNotification:(NSNotification *)notification {
    NSDictionary *body = notification.userInfo;
    NSString *requestUUID = body[@"requestUUID"];
    ASAnisetteDataHandler handler = self.tasks[requestUUID];
    if (handler) {
        self.tasks[requestUUID] = nil;
        NSData *data = body[@"anisetteData"];
        ALTAnisetteData *obj = [NSKeyedUnarchiver unarchivedObjectOfClass:[ALTAnisetteData class] fromData:data error:nil];
        [obj sanitize];
        handler(obj, nil);
    }
}

@end

#endif

@implementation ASAnisetteDataGlobalProvider : ASAnisetteDataProvider

- (void)fetchAnisetteData:(ASAnisetteDataHandler)completion {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
        NSData *data = [NSData dataWithContentsOfURL:self.fetchURL];
        if (!data) {
            NSError *error = [NSError errorWithDomain:ASErrorDomain code:ASErrorFetchAnisetteDataFailed userInfo:@{
                NSLocalizedDescriptionKey: @"Login failed",
                NSLocalizedFailureReasonErrorKey: @"Can not fetch AnisetteData",
                NSLocalizedRecoverySuggestionErrorKey: @"Check the url is valid",
            }];
            completion(nil, error);
            return;
        }
        NSError *error = nil;
        NSDictionary *json = [NSJSONSerialization JSONObjectWithData:data options:kNilOptions error:&error];
        if (error) {
            completion(nil, error);
            return;
        }
        
        ALTAnisetteData *anisette = [[ALTAnisetteData alloc] initWithOriginKeyedJSON:json];
        completion(anisette, nil);
    });
}

@synthesize fetchURL = _fetchURL;
- (NSURL *)fetchURL {
    if (!_fetchURL) {
        _fetchURL = [[NSURL alloc] initWithString:@"https://armconverter.com/anisette/irGb3Quww8zrhgqnzmrx"];
    }
    return _fetchURL;
}

@end
